﻿using System;

namespace PKTools.Scheduler
{
    public class Schedule
    {
        public enum _Type : byte
        {
            Interval = 1,
            Day = 2,
            Week = 4,
            Immediate = 8
        }

        public _Type
            Type { set; get; }
        public TimeSpan // Interval
            Interval { set; get; }
        public bool[]   // Week, Sunday = 0
            WeekDays { set; get; }
        public TimeSpan // Day, Week
            At { set; get; }

        int FindClosestDay(int today, bool[] days)
        {
            for (int i = today; i < 7; i++)
                if (days[i])
                    return i;

            return 7 + FindClosestDay(0, days);
        }

        public DateTime NextExecution(DateTime? executedOn, DateTime currentTime)
        {
            var
                last = executedOn ?? currentTime;

            switch (this.Type)
            {
                case _Type.Interval:
                    return last.Add(this.Interval);
                case _Type.Day:
                    return last.Date.AddDays(1).Add(this.At);
                case _Type.Week:
                    var
                        date = last.Date;
                    return date.AddDays(-(int)date.DayOfWeek).AddDays(FindClosestDay((int)date.DayOfWeek, this.WeekDays)).Add(this.At);
                case _Type.Immediate:
                    return currentTime;
                default:
                    throw new NotSupportedException();
            }
        }

        public override string ToString()
        {
            switch (this.Type)
            {
                case _Type.Interval:
                    return string.Format("every {0} days {1} hours {2} min.", this.Interval.TotalDays, this.Interval.Hours, this.Interval.Minutes);
                case _Type.Day:
                    return string.Format("every day at {0}", this.At);
                case _Type.Week:
                    string
                        temp = string.Empty;

                    for (int i = 0; i < 7; i++)
                        if (this.WeekDays[i])
                            temp += ", " + (DayOfWeek)i;

                    return string.Format("every {0} at {1}", temp.Substring(2), this.At);
                case _Type.Immediate:
                    return "immediate";
                default:
                    throw new NotSupportedException();
            }
        }
    }
}
